﻿#Requires AutoHotkey v2.0
#SingleInstance Force

TraySetIcon 'C:\Users\dkwd\Desktop\Icon图集\ScreenCopy.ico'

CoordMode 'Mouse', 'Screen'
CoordMode 'ToolTip', 'Screen'

#Include 'G:\AHK\Ahk_v2\common\Tip.ahk'

; '#898374'
class Config {
  static useRandomBgc := false ; Not recommend
  static defaultBgc := '00c5cd'
  static guiOption := '+AlwaysOnTop -Caption +ToolWindow +Border'
  static guiTransparent := 160

  static showMask := false
  static maskBgc := 'yellow'
  static maskInitTransparent := 20

  static singleton := false ; if true ,the gui instance will be reused
}

isReady := true

!`:: {
  global
  if !isReady
    return
  isReady := false
  ToolTip 'READY', 100, 50
  Hotkey 'LButton', StartClip, 'On'
  Hotkey 'Esc', Cancel, 'On'
  Mask.Show()
}

Cancel(*) {
  Hotkey 'LButton', 'Off'
  Mask.Close()
  Tip.ShowTip('CANCEL')
}

StartClip(*) {
  g := Config.singleton
    ? GetGui()
    : Gui(Config.guiOption)
  g.BackColor := Config.useRandomBgc
    ? GetRandomColor()
    : Config.defaultBgc
  MouseGetPos &begin_x, &begin_y
  g.Show('x' begin_x ' y' begin_y)
  WinSetTransparent(Config.guiTransparent, 'ahk_id' g.Hwnd)
  last_x := 0, last_y := 0
  while GetKeyState('LButton', 'P') {
    MouseGetPos &end_x, &end_y
    x := End_x < Begin_x ? End_x : Begin_x
    y := End_y < Begin_y ? End_y : Begin_y
    ; caculate gui size
    scope_x := Abs(begin_x - end_x)
    scope_y := Abs(begin_y - end_y)
    if last_x != end_x || last_y != end_y {
      ToolTip(scope_x 'X' scope_y, x, y - 20, 1)
      ToolTip('(' end_x ',' end_y ')', end_x, end_y + 20, 2)
    }
    last_x := end_x
    last_y := end_y
    g.Move(x, y, scope_x, scope_y)
  }
  Hotkey 'LButton', 'Off'
  Hotkey 'Esc', 'Off'
  Mask.Close()
  global isReady := true
  ToolTip
  ToolTip , , , 2
  g.proxy := g.AddText('xp w' scope_x ' h' scope_y,)
  g.proxy.OnEvent('DoubleClick', (*) => WinClose('ahk_id' g.Hwnd))
  fn := MoveWin.Bind(g.Hwnd)
  g.proxy.OnEvent('Click', fn)
  g.OnEvent('ContextMenu', OnCM)
  ClipScreen(g.Hwnd)
}

OnCM(obj, ctrlObj, item, isR, x, y) {
  m := Menu()
  ; m.Add '&ZoomOut', (*) => ZoomOut(obj)
  m.Add '&Save', (*) => SaveToClipBoard(obj.Hwnd)
  m.Show()
}

ZoomOut(g) {
  WinGetPos(&x, &y, &rw, &rh, 'ahk_id' g.Hwnd)

  w := rw + 100
  h := (w / rw) * rh
  g.proxy.Move(, , w, h)
  g.Move(x, y, w, h)

  Sleep 10

  hGuiDC := DllCall('GetDC', 'ptr', g.Hwnd)
  loop 100 {
    g.Move(x, y, rw + A_Index, (A_Index / 100) * (h - rh) + rh)

  }
  DllCall("gdi32.dll\StretchBlt"
    , 'UInt', hGuiDC
    , 'Int', 0, 'Int', 0
    , 'Int', w, 'Int', h
    , 'UInt', hGuiDC
    , 'Int', 0, 'Int', 0
    , 'Int', rw, 'Int', rh, 'UInt', 0xCC0020)
  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hGuiDC)
}

MoveWin(hwnd, *) {
  MouseGetPos(&px, &py)
  WinGetPos(&wx, &wy, , , 'ahk_id' hwnd)
  dx := wx - px, dy := wy - py
  SetWinDelay -1
  While GetKeyState("LButton", "P") {
    MouseGetPos(&nx, &ny)
    WinMove(nx + dx, ny + dy, , , 'ahk_id' hwnd)
  }
}

class Mask extends Gui {
  static insId := ''
  __New() {
    super.__New('+AlwaysOnTop -Caption +ToolWindow')
    this.BackColor := Config.maskBgc
  }
  static Show(*) {
    if !Config.showMask
      return
    ins := Mask()
    ins.Show('Minimize x0 y0 w' A_ScreenWidth ' h' A_ScreenHeight)
    WinSetTransparent(0, 'ahk_id' ins.Hwnd)
    ins.Restore()
    WinSetTransparent(Config.maskInitTransparent, 'ahk_id' ins.Hwnd)
    this.insId := ins.Hwnd
  }
  static Close() {
    try
      WinClose('ahk_id' this.insId)
  }
}


GetGui() {
  static g := Gui(Config.guiOption)
  return g
}

GetRandomColor() {
  rx := Random(0, A_ScreenWidth)
  ry := Random(0, A_ScreenHeight)
  return Config.defaultBgc := PixelGetColor(rx, ry, 'RGB')
}


#Esc:: {
  res := MsgBox('Exit?', , 0x1)
  if res != 'OK'
    return
  ExitApp()
}

!Esc:: {
  Tip.ShowTip('Clear all')
  for w in WinGetList('ahk_pid ' ProcessExist())
    try
      WinClose 'ahk_id' w
}

ClipScreen(hwnd) {
  hdd_frame := DllCall("GetDC", 'UInt', 0)
  hdc_frame := DllCall("GetDC", 'UInt', hwnd)
  ; WinSetTransparent(255, 'ahk_id' hwnd) ; is unnecessary
  WinSetTransColor(Config.defaultBgc, 'ahk_id' hwnd)
  WinGetPos(&x, &y, &Rx, &Ry, 'ahk_id' hwnd)

  DllCall("gdi32.dll\StretchBlt", 'UInt', hdc_frame, 'Int'
    , 0, 'Int', 0, 'Int', Rx, 'Int', Ry
    , 'UInt', hdd_frame, 'UInt', x, 'UInt', y
    , 'Int', Rx, 'Int', Ry, 'UInt', 0xCC0020) ; SRCCOPY
  Tip.ShowTip('OVER')

  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hdc_frame)
  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hdd_frame)
}

SaveToClipBoard(hwnd) {
  WinGetPos(, , &w, &h, 'ahk_id' hwnd)
  hGuiDC := DllCall('GetDC', 'ptr', hwnd)
  hMemDC := DllCall("CreateCompatibleDC", "Ptr", 0)
  hBitmap := DllCall("CreateCompatibleBitmap", "ptr", hGuiDC, "int", w, "int", h)
  hOldBitmap := DllCall("SelectObject", "Ptr", hMemDC, "Ptr", hBitmap)
  DllCall("BitBlt", "Ptr", hMemDC, "int", 0, "int", 0, "int", w, "int", h
    , "Ptr", hGuiDC, "int", 0, "int", 0, "uint", 0xCC0020)
  hOldBitmap := DllCall("SelectObject", "Ptr", hMemDC, "Ptr", hOldBitmap)
  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hMemDC)
  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hGuiDC)
  ; use clipboard
  DllCall("OpenClipboard", "Ptr", 0)
  DllCall("EmptyClipboard")
  DllCall("SetClipboardData", "uint", 2, "Ptr", hBitmap)
  DllCall("CloseClipboard")

  DllCall("DeleteObject", "Ptr", hBitmap)

  Tip.ShowTip('已保存喵~')
}